package org.red_cross_service.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import org.red_cross_service.domain.entity.ActivityEntity;
import org.red_cross_service.domain.entity.LearnRecordEntity;
import org.red_cross_service.domain.entity.VideoEntity;
import org.red_cross_service.mapper.ActivityMapper;
import org.red_cross_service.mapper.LearnRecordMapper;
import org.red_cross_service.mapper.VideoMapper;
import org.red_cross_service.utils.QueryWrapperUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.math.BigDecimal;
import java.util.*;

@Service
public class VideoService {

    @Autowired
    private VideoMapper videoMapper;

    @Autowired
    private ActivityMapper activityMapper;

    @Autowired
    private LearnRecordMapper learnRecordMapper;

    public List<VideoEntity> list(VideoEntity videoEntity) {
        return
                videoMapper.selectList(
                        QueryWrapperUtils.buildQuery(videoEntity)
                                //根据sort字段升序排序
                                .orderByAsc("sort")
                );
    }

    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public int add(VideoEntity videoEntity) {
        videoMapper.insert(videoEntity);
        videoEntity = videoMapper.selectById(videoEntity.getVideoId());
        if (updateActivity(videoEntity.getVideoId(), 0, 0) < 1) {
            //事务回滚
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new RuntimeException("更新activity表失败");
        }
        return 1;
    }

    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public int delete(Integer videoId){
        VideoEntity oriVideoEntity = videoMapper.selectById(videoId);
        List<VideoEntity> videoEntityList = list(new VideoEntity());
        List<Integer> ids = videoEntityList.stream().map(VideoEntity::getVideoId).toList();
        int index = ids.indexOf(oriVideoEntity.getVideoId());
        videoMapper.deleteById(videoId);
        if (updateActivity(videoId, 1, index) < 1) {
            //事务回滚
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new RuntimeException("更新activity表失败");
        }

        return 1;
    }

    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public int update(VideoEntity videoEntity){
        VideoEntity oriVideoEntity = videoMapper.selectById(videoEntity.getVideoId());
        if (Objects.equals(videoEntity.getSort(), oriVideoEntity.getSort())) {
            videoMapper.updateById(videoEntity);
            if (updateActivity(videoEntity.getVideoId(), 2, 0) < 1) {
                //事务回滚
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                throw new RuntimeException("更新activity表失败");
            }
        } else {
            List<VideoEntity> videoEntityList = list(new VideoEntity());
            List<Integer> ids = videoEntityList.stream().map(VideoEntity::getVideoId).toList();
            int index = ids.indexOf(oriVideoEntity.getVideoId());
            videoMapper.updateById(videoEntity);
            //立即执行事务
            if (updateActivity(oriVideoEntity.getVideoId(), 3, index) < 1) {
                //事务回滚
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                throw new RuntimeException("更新activity表失败");
            }
        }

        return 1;
    }

    public VideoEntity selectOne(VideoEntity videoEntity) {
        return videoMapper.selectById(videoEntity.getVideoId());
    }

    @Transactional(rollbackFor = Exception.class)
    public int updateActivity(Integer id, int type, int oriIndex) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        List<VideoEntity> videoEntityList = list(new VideoEntity());
        Long sumLength = videoMapper.sumLength();
        //更新activity表所有行的videoInfo字段
        if (activityMapper.selectCount(new QueryWrapper<>())==0){
            return 1;
        }
        activityMapper.update(
                new ActivityEntity().setVideosInfo(
                        objectMapper.writeValueAsString(videoEntityList)
                ).setVideosLength(BigDecimal.valueOf(sumLength)),
                new QueryWrapper<>()
        );
        List<Integer> ids = videoEntityList.stream().map(VideoEntity::getVideoId).toList();
        int index = ids.indexOf(id);
        if (learnRecordMapper.selectCount(new QueryWrapper<>())==0){
            return 1;
        }
        List<LearnRecordEntity> recordEntityList = learnRecordMapper.selectList(new QueryWrapper<>());

        for (LearnRecordEntity recordEntity : recordEntityList) {
            Integer[] videoProcessList = objectMapper.readValue(recordEntity.getVideosProcess(), Integer[].class);
            //videoProcessList int[] 转 ArrayList<Integer>
            ArrayList<Integer> list = new ArrayList<>();
            Collections.addAll(list, videoProcessList);
            int videosStatus = recordEntity.getVideosStatus();
            //创建掩码
            int mask,oriMask,oriMove;
            switch (type) {
                //插入视频
                case 0:
                    mask = (1 << index) - 1;
                    videosStatus = (videosStatus & mask) + (videosStatus >> index << (index + 1));
                    recordEntity.setVideosStatus(videosStatus);
                    list.add(index, 0);
                    break;
                //删除视频
                case 1:
                    oriMask = (1 << (oriIndex + 1 - 1)) - 1;
                    oriMove = oriIndex + 1;
                    videosStatus = (videosStatus >> oriMove << (oriMove - 1)) + (videosStatus & oriMask);
                    list.remove(oriIndex);
                    break;
                case 2:
                    list.set(index, 0);
                    videosStatus = videosStatus &~ (1 << index);
                    break;
                default:
                    oriMask = (1 << (oriIndex + 1 - 1)) - 1;
                    oriMove = oriIndex + 1;
                    videosStatus = (videosStatus >> oriMove << (oriMove - 1)) + (videosStatus & oriMask);
                    Integer oriProcess = list.get(oriIndex);
                    list.remove(oriIndex);
                    mask = (1 << index) - 1;
                    videosStatus = (videosStatus & mask) + (videosStatus >> index << (index + 1));
                    recordEntity.setVideosStatus(videosStatus);
                    list.add(index, oriProcess);
                    break;
            }
            recordEntity.setVideosStatus(videosStatus);
            recordEntity.setVideosProcess(objectMapper.writeValueAsString(list));
        }
        //批量更新学习记录
        if (learnRecordMapper.updateBatch(recordEntityList) <= 0) {
            return 0;
        }
        return 1;
    }

}
